package se.hiq.wineo.client.widgets.common;

import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HasValue;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;

/**
 * This Widgets presents all the values of an enum in a listbox and has functionality for selecting
 * any given such value. The listbox also contains an empty field.
 * 
 * @author joakimsah
 *
 */
public class EnumFieldWidget<T extends Enum<?>> extends Composite implements HasValue<T> {

	// Widgets in this Composite
	private Grid mainPanel;
	private Label nameLabel;
	private ListBox valueListBox;
	
	private final T[] values;
	
	public EnumFieldWidget(T selected, T[] values) {
		this(null, selected, values, null);
	}
	
	public EnumFieldWidget(String name, T selected, T[] values, String labelWidth) {
		this.values = values;
		
		mainPanel = new Grid(1, 2);
		nameLabel = new Label(name);
		if (labelWidth != null) {
			nameLabel.setWidth(labelWidth);
		}
		valueListBox = new ListBox();
		populateListBox(selected);
		
		if (name != null) {
			mainPanel.setWidget(0, 0, nameLabel);
			mainPanel.setWidget(0, 1, valueListBox);
		} else {
			mainPanel.setWidget(0, 0, valueListBox);
		}
		initWidget(mainPanel);
	}
	
	/**
	 * Get selected value
	 * 
	 * @param values
	 * @return Selected value or null if none selected
	 */
	@Override
	public T getValue() {
		String selectedValue = getSelectedValue();
		if (selectedValue != null) {
			for (T v : values) {
				if (v.toString().equals(selectedValue)) {
					return v;
				}
			}
		}
		return null;
	}

	/**
	 * Select the given enum value
	 * 
	 * @param selected Given enum value, must be same type as Enum given in constructor
	 */
	@Override
	public void setValue(T value) {
		if (value == null) {
			valueListBox.setSelectedIndex(0);
		} else {
			for (int i = 0; i < valueListBox.getItemCount(); i++) {
				if (value.toString().equals(valueListBox.getItemText(i))) {
					valueListBox.setSelectedIndex(i);
					break;
				}
			}
		}
	}

	@Override
	public void setValue(T value, boolean fireEvents) {
		throw new RuntimeException("Operation not supported");
	}

	@Override
	public HandlerRegistration addValueChangeHandler(ValueChangeHandler<T> handler) {
		throw new RuntimeException("Operation not supported");
	}
	
	/**
	 * Set whether the input part of this component is enabled
	 * 
	 * @param enabled true/false
	 */
	public void setEnabled(boolean enabled) {
		valueListBox.setEnabled(enabled);
	}
	
	// ----- Private methods -----
	
	private void populateListBox(T selected) {
		int idx = 1;
		valueListBox.addItem("");
		valueListBox.setSelectedIndex(0);
		for (T s : values) {
			valueListBox.addItem(s.toString());
			if (s.equals(selected)) {
				valueListBox.setSelectedIndex(idx);
			}
			idx++;
		}
	}
	
	private String getSelectedValue() {
		if (valueListBox.getSelectedIndex() >= 0) {
			return valueListBox.getItemText(valueListBox.getSelectedIndex());
		} else {
			return null;
		}
	}

}
